package com.shanjupay.common.util;

import com.alibaba.fastjson.JSONObject;
import com.google.zxing.*;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.FileSystems;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Random;

/**
 * Description: 二维码制作工具类
 */
public class QRCodeUtil {
    private static final String CHARSET = "utf-8";
    private static final String FORMAT_NAME = "JPG";
    // 二维码尺寸
    private static final int QRCODE_SIZE = 300;
    // LOGO宽度
    private static final int WIDTH = 60;
    // LOGO高度
    private static final int HEIGHT = 60;


    /**
     * 生成二维码
     *
     * @param content      源内容
     * @param imgPath      生成二维码保存的路径
     * @param needCompress 是否要压缩
     * @return 返回二维码图片
     * @throws Exception
     */
    private static BufferedImage createImage(String content, String imgPath, boolean needCompress) throws Exception {
        Hashtable hints = new Hashtable();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE,
                hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        if (imgPath == null || "".equals(imgPath)) {
            return image;
        }
        // 插入图片
        QRCodeUtil.insertImage(image, imgPath, needCompress);
        return image;
    }

    /**
     * 在生成的二维码中插入图片
     *
     * @param source
     * @param imgPath
     * @param needCompress
     * @throws Exception
     */
    private static void insertImage(BufferedImage source, String imgPath, boolean needCompress) throws Exception {
        File file = new File(imgPath);
        if (!file.exists()) {
            System.err.println("" + imgPath + "   该文件不存在！");
            return;
        }
        Image src = ImageIO.read(new File(imgPath));
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        if (needCompress) { // 压缩LOGO
            if (width > WIDTH) {
                width = WIDTH;
            }
            if (height > HEIGHT) {
                height = HEIGHT;
            }
            Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
            BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics g = tag.getGraphics();
            g.drawImage(image, 0, 0, null); // 绘制缩小后的图
            g.dispose();
            src = image;
        }
        // 插入LOGO
        Graphics2D graph = source.createGraphics();
        int x = (QRCODE_SIZE - width) / 2;
        int y = (QRCODE_SIZE - height) / 2;
        graph.drawImage(src, x, y, width, height, null);
        Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
        graph.setStroke(new BasicStroke(3f));
        graph.draw(shape);
        graph.dispose();
    }

    /**
     * 生成带logo二维码，并保存到磁盘
     *
     * @param content
     * @param imgPath      logo图片
     * @param destPath
     * @param needCompress
     * @throws Exception
     */
    public static String encode(String content, String imgPath, String destPath, boolean needCompress) throws Exception {
        BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
        mkdirs(destPath);
        String file = new Random().nextInt(99999999) + ".jpg";//生成随机文件名
        ImageIO.write(image, FORMAT_NAME, new File(destPath + "/" + file));
        return file;
    }

    public static void mkdirs(String destPath) {
        File file = new File(destPath);
        // 当文件夹不存在时，mkdirs会自动创建多层目录，区别于mkdir。(mkdir如果父目录不存在则会抛出异常)
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }

    public static void encode(String content, String imgPath, String destPath) throws Exception {
        QRCodeUtil.encode(content, imgPath, destPath, false);
    }

    public static void encode(String content, String destPath, boolean needCompress) throws Exception {
        QRCodeUtil.encode(content, null, destPath, needCompress);
    }

    public static void encode(String content, String destPath) throws Exception {
        QRCodeUtil.encode(content, null, destPath, false);
    }

    public static void encode(String content, String imgPath, OutputStream output, boolean needCompress)
            throws Exception {
        BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
        ImageIO.write(image, FORMAT_NAME, output);
    }

    public static void encode(String content, OutputStream output) throws Exception {
        QRCodeUtil.encode(content, null, output, false);
    }


    /**
     * 从二维码中，解析数据
     *
     * @param file 二维码图片文件
     * @return 返回从二维码中解析到的数据值
     * @throws Exception
     */
    public static String decode(File file) throws Exception {
        BufferedImage image;
        image = ImageIO.read(file);
        if (image == null) {
            return null;
        }
        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Result result;
        Hashtable hints = new Hashtable();
        hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
        result = new MultiFormatReader().decode(bitmap, hints);
        String resultStr = result.getText();
        return resultStr;
    }

    public static String decode(String path) throws Exception {
        return QRCodeUtil.decode(new File(path));
    }








    private static final Logger log = LoggerFactory.getLogger(QRCodeUtil.class);

    /**
     *
     * 生成二维码文件测试
     * @param filePath 文件路径
     * @param fileName 文件名
     * @param number 编号
     * @param phone 手机号
     * @see [类、类#方法、类#成员]
     */
    public static void generatEncodeTest(String filePath, String fileName, String number, String phone)
    {

        int width = 200; // 图像宽度
        int height = 200; // 图像高度
        String format = "png";// 图像类型

        JSONObject json = new JSONObject();
        json.put("number",number);
        json.put("phone", phone);
        String content = json.toJSONString();// 内容

        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");

        try
        {
            BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);// 生成矩阵
            String path = FileSystems.getDefault().getPath(filePath, fileName).toString();
            File file = new File(path);
            MatrixToImageWriter.writeToFile(bitMatrix, format, file);// 输出图像
            System.out.println("二维码输出成功");
            System.out.println("图片地址：" + filePath + fileName);
            System.out.println("---------------------------");
        }
        catch (WriterException e)
        {
            e.printStackTrace();
            System.out.println("二维码输出异常");
        }
        catch (IOException e)
        {
            e.printStackTrace();
            System.out.println("二维码输出异常");
        }
    }

    /**
     *
     * 生成二维码输出流
     *  在jsp页面中直接展示时使用
     *  无须保存 即生成即展示
     * @param response
     * @param number 编号
     * @param phone 手机号
     * @see [类、类#方法、类#成员]
     */
    public static void generatEncode(HttpServletResponse response, String number, String phone)
    {
        JSONObject json = new JSONObject();
        json.put("number",number);
        json.put("phone", phone);
        String content = json.toJSONString();// 内容

        int width = 200; // 图像宽度
        int height = 200; // 图像高度
        String format = "png";// 图像类型

        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");

        try
        {

            BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);// 生成矩阵
            MatrixToImageWriter.writeToStream(bitMatrix, format, response.getOutputStream());// 输出图像
            log.info("二维码输出成功");
        }
        catch (WriterException e)
        {
            e.printStackTrace();
            log.error("二维码输出异常");
        }
        catch (IOException e)
        {
            e.printStackTrace();
            log.error("二维码输出异常");
        }
    }

    /**
     *
     * 解析二维码内容测试
     * @param filePath 二维码绝对路径
     * @see [类、类#方法、类#成员]
     */
    public static void parseDecodeTest(String filePath)
    {
        BufferedImage image;
        try
        {
            image = ImageIO.read(new File(filePath));
            LuminanceSource source = new BufferedImageLuminanceSource(image);
            Binarizer binarizer = new HybridBinarizer(source);
            BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);

            Map<DecodeHintType, Object> hints = new HashMap<DecodeHintType, Object>();
            hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");

            Result result = new MultiFormatReader().decode(binaryBitmap, hints);// 对图像进行解码
            JSONObject content = JSONObject.parseObject(result.getText());

            StringBuffer sb = new StringBuffer();
            sb.append("编号：")
                    .append(content.getString("number"))
                    .append("\r\n")
                    .append("手机号码:")
                    .append(content.getString("phone"));
            String returnText = sb.toString();
            System.out.println(returnText);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        catch (NotFoundException e)
        {
            e.printStackTrace();
        }
    }







}


//package com.shanjupay.common.util;
//
//import com.google.zxing.BarcodeFormat;
//import com.google.zxing.EncodeHintType;
//import com.google.zxing.MultiFormatWriter;
//import com.google.zxing.common.BitMatrix;
//import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
//import org.apache.commons.logging.Log;
//import org.apache.commons.logging.LogFactory;
//
//import javax.imageio.ImageIO;
//import java.awt.image.BufferedImage;
//import java.io.File;
//import java.io.IOException;
//import java.util.Hashtable;
//import java.util.Map;
//
///**
// *
// * 使用了google zxing作为二维码生成工具
// */
//public class ZxingUtils {
//	private static Log log = LogFactory.getLog(ZxingUtils.class);
//
//    private static final int BLACK = 0xFF000000;
//    private static final int WHITE = 0xFFFFFFFF;
//
//    private static BufferedImage toBufferedImage(BitMatrix matrix) {
//        int width = matrix.getWidth();
//        int height = matrix.getHeight();
//        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//        for (int x = 0; x < width; x++) {
//            for (int y = 0; y < height; y++) {
//                image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
//            }
//        }
//        return image;
//    }
//
//    private static void writeToFile(BitMatrix matrix, String format, File file) throws IOException {
//        BufferedImage image = toBufferedImage(matrix);
//        if (!ImageIO.write(image, format, file)) {
//            throw new IOException("Could not write an image of format " + format + " to " + file);
//        }
//    }
//
//    /** 将内容contents生成长宽均为width的图片，图片路径由imgPath指定
//     */
//    public static File getQRCodeImge(String contents, int width, String imgPath) {
//        return getQRCodeImge(contents, width, width, imgPath);
//    }
//
//    /** 将内容contents生成长为width，宽为width的图片，图片路径由imgPath指定
//     */
//	public static File getQRCodeImge(String contents, int width, int height, String imgPath) {
//		try {
//            Map<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
//            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
//            hints.put(EncodeHintType.CHARACTER_SET, "UTF8");
//
//			BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height, hints);
//
//            File imageFile = new File(imgPath);
//			writeToFile(bitMatrix, "png", imageFile);
//
//            return imageFile;
//
//		} catch (Exception e) {
//			log.error("create QR code error!", e);
//            return null;
//		}
//	}
//}
